
#include "esp_log.h"

#include "xlx_tmsapi.h"
#include "xlx_func.h"
#include "xlx_platform.h"
#include "xlx_config.h"
#include "xlx_os.h"
#include "xlx_core.h"

#include "netdb.h"

static const char* TAG = "TmsApi";

#ifdef TUTU_CODE_EC618_BSJ
    #include "errno.h"
    #include "netdb.h"
    #include "sys/socket.h"
#endif

//异或签名计算
static char tutu_xorop(char *data,int len){
    char tmp = data[0];
    int i = 0;
    for (i = 1; i < len; i++) {
        tmp ^= data[i];
    }
    return tmp;
}

//------------------------------------------------------------------------------------------------

static void tutu_data_put(TMSContext *m,const char *data,int len){
    if(data){
        xlx_print_hex(XLX_TMS_WRITE,data,len);
        send( m->sockfd, data, len, 0);
    }
}


//填充head
char* tmsapi_fill_head(u8 cmd,u16 seq,char *imei,char *sndbuf,int bodylen){
    int headlen = sizeof(TMSMsgHead);

    TMSMsgHead head = {0};
    head.fixed = 0xfa;
    head.cmd = cmd;
    head.body_len = bodylen;
    head.seq = seq;
    memcpy(head.imei,imei,8);
    
    
    head.seq = xlx_htons(head.seq);
    head.body_len = xlx_htons(head.body_len);
 
    
    //把协议头数据写入到缓存
    memcpy(sndbuf, &head, headlen);

    return sndbuf + headlen;
}

//body追加一个字符
char *tmsapi_append_body_char(char *p,char d){
    *p = d;
    p++;
    return p;
}

//body追加一段数据
char *tmsapi_append_body_data(char *p,char *data,int data_len){
    memcpy(p,data,data_len);
    p += data_len;
    return p;
}

//追加签名
void tmsapi_append_xor_sign(char *begin,char *end){
    char xorop = tutu_xorop(begin,end - begin);
    *end = xorop;
}

//设置参数
void tmsapi_set_params(TMSContext *m,char *imei,char *chip_id){
    if(imei){
        memcpy(m->imei,imei,8);
    }
    
    if(chip_id){
        memcpy(m->chip_id,chip_id,CHIPID_LEN);
    }
}

//设置回调
void tmsapi_set_delegate(TMSContext *m,TMSDelegate *delegate){
    if(delegate){
        if(delegate->on_agps_file_recv){
            m->d.on_agps_file_recv = delegate->on_agps_file_recv;
        }
        
        if(delegate->on_cloud_read_value){
            m->d.on_cloud_read_value = delegate->on_cloud_read_value;
        }
        
        if(delegate->on_cmd){
            m->d.on_cmd = delegate->on_cmd;
        }
        
        if(delegate->on_ota_file_recv){
            m->d.on_ota_file_recv = delegate->on_ota_file_recv;
        }

        if(delegate->on_ota_start){
            m->d.on_ota_start = delegate->on_ota_start;
        }
    }
}

void tmsapi_close_socket(TMSContext *m){
    if (m) {
        if(m->sockfd != 0){

        TUTU_LOGI(TAG, "tmsapi_close_socket(%d) ",m->sockfd)
        close(m->sockfd);

        }
        m->recv_wpos = 0;
        m->sockfd = -1;
    }
}

//请求下载agps文件
// gps_type:
//  1.中科微
//  2.u-blox agps 7代
//  3.u-blox apgs 8代
//  4.泰斗
//
// baseinfo:
//  基站信息MCC,MNC,LAC,Cell,ID, -SPW
void tmsapi_req_agps_file(TMSContext *m,char gps_type,char *baseinfo){
    char sndbuf[64]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);
    
    m->seq++;

    //baseinfo
    //mcc,mnc,lac,cellid,-spw

    bodylen = 3 + strlen(baseinfo);

    p = tmsapi_fill_head(0x12,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_char(p,gps_type);
    p = tmsapi_append_body_char(p,1);
    p = tmsapi_append_body_char(p,4);
    p = tmsapi_append_body_data(p,baseinfo,strlen(baseinfo));
    tmsapi_append_xor_sign(sndbuf,p);
    
    tutu_data_put(m,sndbuf,headlen + bodylen + 1);

    TUTU_LOGI(TAG, "req agps file!");
}

//开机需要上报的固定信息
void tmsapi_req_deviceinfo1(TMSContext *m,TMSDeviceUpBody1 *body1,char *str_ver){
    char sndbuf[128]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    m->seq++;

    body1->channel = 1;
    bodylen = sizeof(TMSDeviceUpBody1) + strlen(str_ver) + 1;

    if(headlen + bodylen + 1 >= 128){
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }
    

    p = tmsapi_fill_head(0x11,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)body1,sizeof(TMSDeviceUpBody1));
    p = tmsapi_append_body_data(p,str_ver,strlen(str_ver));
    p = tmsapi_append_body_char(p,0);
    tmsapi_append_xor_sign(sndbuf,p);

    tutu_data_put(m,sndbuf,headlen + bodylen + 1);
    

    TUTU_LOGI(TAG, "req deviceinfo1!");
}

//定时信息
void tmsapi_req_deviceinfo2(TMSContext *m,TMSDeviceUpBody2 *body2,char *str_lbs){
    char sndbuf[128]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    m->seq++;

    body2->channel = 2;
    bodylen = sizeof(TMSDeviceUpBody2);
    
    if(str_lbs){
        bodylen += strlen(str_lbs);
    }
    

    if(headlen + bodylen + 1 >= 128){
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }

    body2->vbat = xlx_htons(body2->vbat);
    body2->vin = xlx_htons(body2->vin);

    p = tmsapi_fill_head(0x11,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)body2,sizeof(TMSDeviceUpBody2));
    if(str_lbs && strlen(str_lbs) > 0){
        p = tmsapi_append_body_data(p,str_lbs,strlen(str_lbs));
    }
    tmsapi_append_xor_sign(sndbuf,p);


    tutu_data_put(m,sndbuf,headlen + bodylen + 1);
    

    TUTU_LOGI(TAG, "req deviceinfo2!");

}

//事件信息
void tmsapi_req_deviceinfo3(TMSContext *m,TMSDeviceUpBody3 *body3,char *str,int len){
    char sndbuf[128]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    m->seq++;

    body3->channel = 3;
    bodylen = sizeof(TMSDeviceUpBody3) + len;

    if(headlen + bodylen + 1 >= 128){
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }

    body3->event_type = xlx_htons(body3->event_type);
    u32 atime = body3->time & 0xffffffff;
    u32 btime = (body3->time >> 32) & 0xffffffff;
    body3->time = ((u64)(xlx_htonl(atime)) << 32) | xlx_htonl(btime);
    
    p = tmsapi_fill_head(0x11,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)body3,sizeof(TMSDeviceUpBody3));
    p = tmsapi_append_body_data(p,str,len);
    tmsapi_append_xor_sign(sndbuf,p);


    tutu_data_put(m,sndbuf,headlen + bodylen + 1);
    

    TUTU_LOGI(TAG, "req deviceinfo3!");
}

//上传日志到tms服务器,log不能长度不能超过250
void tmsapi_req_uploadlog(TMSContext *m,char *log,int log_len){
    char sndbuf[512]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    m->seq++;

    bodylen = 1 + CHIPID_LEN + 1 + 1 + log_len;

    if(headlen + bodylen + 1 > 510){
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }


    p = tmsapi_fill_head(0x11,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_char(p,4);
    p = tmsapi_append_body_data(p,(char*)m->chip_id,CHIPID_LEN);
    p = tmsapi_append_body_char(p,1);//TLV 类型
    p = tmsapi_append_body_char(p,log_len);// TLV 长度
    p = tmsapi_append_body_data(p,log,log_len);//TLV 值
    tmsapi_append_xor_sign(sndbuf,p);

    tutu_data_put(m,sndbuf,headlen + bodylen + 1);
}

//请求读取云端参数
void tmsapi_req_read_cloud_args(TMSContext *m,char group_id){
    char sndbuf[64]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    m->seq++;

    bodylen = CHIPID_LEN + 1;


    p = tmsapi_fill_head(0x18,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)m->chip_id,CHIPID_LEN);
    p = tmsapi_append_body_char(p,group_id);
    tmsapi_append_xor_sign(sndbuf,p);
    tutu_data_put(m,sndbuf,headlen + bodylen + 1);
    

    TUTU_LOGI(TAG, "req read cloud args!");
}

//请求写云端参数
void tmsapi_req_write_cloud_args(TMSContext *m,char group_id,char *text,int text_len){
    char sndbuf[512]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    m->seq++;
    bodylen = CHIPID_LEN + 1 + text_len;

    if(text_len > 200 || (headlen + bodylen + 1) > 510){
        //参数长度不能超过200个
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }


    p = tmsapi_fill_head(0x19,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)(m->chip_id),CHIPID_LEN);
    p = tmsapi_append_body_char(p,group_id);
    p = tmsapi_append_body_data(p,text,text_len);
    tmsapi_append_xor_sign(sndbuf,p);

    //发送数据
    tutu_data_put(m,sndbuf,headlen + bodylen + 1);
    
    
    TUTU_LOGI(TAG, "req write cloud args!");
}

//上报ota升级情况到服务器
//status:
//  0x01. 待升级
//  0x02. 升级中
//  0x03. 升级成功,上报版本号给服务器比对
//  0x04. 任务过期
//  0x05. 取消升级
//  0x06. 任务失败
void tmsapi_req_upload_ota_status(TMSContext *m,uint32_t tid,char status,char *version){
    char sndbuf[128]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);
    uint32_t _tid = xlx_htonl(tid);

    m->seq++;

    bodylen = 1 + 4;
    if(version){
        bodylen += strlen(version);
    }

    if(bodylen + headlen + 1 > 128){
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }
    

    p = tmsapi_fill_head(0x17,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)(&_tid),4);
    p = tmsapi_append_body_char(p,status);
    if(version){
        p = tmsapi_append_body_data(p,version,strlen(version));
    }

    tmsapi_append_xor_sign(sndbuf,p);

    //发送数据
    tutu_data_put(m,sndbuf,headlen + bodylen + 1);

    TUTU_LOGI(TAG, "upload ota result=%d",status);
}

// 请求下载ota文件，pkgseq从1开始,分片大小 = pkg_size *128
void tmsapi_req_ota_file(TMSContext *m,uint32_t tid,uint32_t pkgseq,char pkg_size){
    char sndbuf[64]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);
    uint32_t _tid = xlx_htonl(tid);
    uint32_t _pkgseq = xlx_htonl(pkgseq);

    m->tid = tid;
    //printf("req_ota_file tid=%d seq=%d\n",tid,pkgseq);

    bodylen = 4 + 4 + 1;
    m->seq++;

    p = tmsapi_fill_head(0x16,m->seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_data(p,(char*)(&_tid),4);
    p = tmsapi_append_body_data(p,(char*)(&_pkgseq),4);
    p = tmsapi_append_body_char(p,pkg_size);
    tmsapi_append_xor_sign(sndbuf,p);

    //发送数据
    tutu_data_put(m,sndbuf,headlen + bodylen + 1);

    TUTU_LOGI(TAG, "req ota file [%ld] [%ld]",tid,pkgseq);
}

//响应服务器下发的指令
void tmsapi_rsp_command(TMSContext *m,u16 seq,int cmd_type,char *rsp_text){
    char sndbuf[128]={0};
    char *p = sndbuf;
    int bodylen = 0;
    int headlen = sizeof(TMSMsgHead);

    bodylen = 1 + strlen(rsp_text);

    if (bodylen + headlen >= 128){
        TUTU_LOGI(TAG, "%s,%d  head + body > sndbuf size",__func__,__LINE__);
        return;
    }

    p = tmsapi_fill_head(0x15,seq,m->imei,sndbuf,bodylen);
    p = tmsapi_append_body_char(p,(char)cmd_type);
    p = tmsapi_append_body_data(p,rsp_text,strlen(rsp_text));
    tmsapi_append_xor_sign(sndbuf,p);

    tutu_data_put(m,sndbuf,headlen + bodylen + 1);



    //xlx_print_hex("rsp cmd",sndbuf,headlen + bodylen + 1);
    TUTU_LOGI(TAG, "rsp command!");
}

//--------------------------------------parse----------------------------------------------

//处理agps信息
void tmsapi_parse_agps(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len > 0){
        int rseq = data[0];
        //printf("rseq=%d\n",rseq);
        if(rseq == 0 && len >= sizeof(TMSAgps0Pkg)){
            TMSAgps0Pkg *p = (TMSAgps0Pkg *)data;
            if(p){
                m->agps_file_size = xlx_htons(p->agps_file_size);
            }
            
            TUTU_LOGI(TAG, "tms year=%d mon=%d day=%d %d:%d:%d\n",xlx_htons(p->year),p->mon,p->day,p->hour,p->min,p->sec);
        }else{
            //合并所有包，组成apgs文件
            //callback(data+1,len-1);
            if(m->d.on_agps_file_recv){
                m->d.on_agps_file_recv(m->agps_file_size,data+1,len-1);
            }
        }
    }
}

//处理透传指令
void tmsapi_parse_command(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len > 0){
        int t = data[0];//指令类型
        char *cmd = data + 1;
        int cmd_len = len - 1;
        cmd[cmd_len] = '\0';
        //printf("recv command string:%s\n",cmd);

        if(strncmp("<FOTA=",cmd,6) == 0){
            //收到服务器投放的ota命令
            int i = 0;
            int j = 0;
            char *cols[6] = {0};
            char *p = cmd + 6;
            cols[j++] = p;
            for (i = 0; i < len - 6; i++)
            {
                char c = *p;
                if(c == '>'){
                    *p = '\0';
                    break;
                }
                
                if(c == '|'){
                    *p = '\0';
                    p++;

                    if(j > 5){
                        break;
                    }

                    cols[j++] = p; 
                }else{
                    p++;
                }
            }
            
            TMSOtaInfo info = {0};
            info.tid = atoi(cols[0]);
            info.delay = atoi(cols[1]);
            info.file_type = atoi(cols[2]);
            info.ota_file_size = atoi(cols[3]);
            strncpy(info.md5,cols[4],32);
            strncpy(info.version,cols[5],32);

            m->ota_file_size = info.ota_file_size;
            m->tid = info.tid;

            if(m->d.on_ota_start){
                m->d.on_ota_start(t,&info);
            }
        }else{
            //回调给业务层处理指令
            if(m->d.on_cmd){
                m->d.on_cmd(t,xlx_htons(h->seq),cmd);
            }
        }
    }
}

//处理服务器响应的终端信息
void tmsapi_parse_device(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len > 0){
        // char rspcode = data[0];//应答结果
    }
}

//服务器响应 读参数
void tmsapi_parse_read_args(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len > 1){
        char group_id = data[0];
        char *value = data + 1;
        int value_len = len - 1;
        value[value_len] = '\0';
        TUTU_LOGI(TAG, "read args -> group_id=%d value=%s\n",group_id,value);
        if(m->d.on_cloud_read_value){
            m->d.on_cloud_read_value(group_id,value,value_len);
        }
    }
}

//服务器响应 写参数
void tmsapi_parse_write_args(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len >= 2){
        char group_id = data[0];
        char rsp_code = data[1];
        TUTU_LOGI(TAG, "write args - > group_id=%d rsp=%d\n",group_id,rsp_code);
    }
}

//服务器升级任务-文件分片下载
void tmsapi_parse_ota_task(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len >= 8){
        // uint32_t *ptid = (uint32_t*)data;
        uint32_t *pseq = (uint32_t*)(data+4);
        char *raw = (data + 8);

        if(m->d.on_ota_file_recv){
            char code = m->d.on_ota_file_recv(m->ota_file_size,raw,len - 8);
            if(code == 1){
                tmsapi_req_ota_file(m,m->tid,xlx_htonl(*pseq)+1,8);
            }
        }
    }
}

// 服务器响应-ota更新状态
void tmsapi_parse_ota_status(TMSContext *m,TMSMsgHead* h,char *data,int len){
    if(len >= 5){
        // uint32_t tid = *((uint32_t*)data);
        // char rsp_code = data[4];
    }
}

//---------------------------------------------------------------------------------------------------------------




void tutu_dispatch(TMSContext *m,TMSMsgHead* h,char *data,int len){
    char xorop = tutu_xorop(data,len -1);
    char sign = data[len - 1];
    if(xorop == sign){//校验签名是否正确
        char *body_data = data + 14;
        int body_len = len - 1 - 14;
        switch(h->cmd){
            case 0x92://下载apgs文件
                tmsapi_parse_agps(m,h,body_data,body_len);
            break;
            case 0x95://处理透传指令
                tmsapi_parse_command(m,h,body_data,body_len);
            break;
            case 0x91://处理终端信息上报结果
                tmsapi_parse_device(m,h,body_data,body_len);
            break;
            case 0x98://服务器响应参数读取
                tmsapi_parse_read_args(m,h,body_data,body_len);
            break;
            case 0x99://服务器响应参数写入情况
                tmsapi_parse_write_args(m,h,body_data,body_len);
            break;
            case 0x96://服务器ota升级任务-文件分片下载
                tmsapi_parse_ota_task(m,h,body_data,body_len);
            break;
            case 0x97://服务器响应更新ota的状态
                tmsapi_parse_ota_status(m,h,body_data,body_len);
            break;
        }
        //xlx_print_hex("tutu_dispatch",data,len);
    }else{
        TUTU_LOGI(TAG, "tms recv data sign failt!!!!\n");
    }
}

//数据包，解包处理
void tutu_process(TMSContext *m){
    int n = 0;
    TMSMsgHead *h = NULL;
    int body_len = 0;
    int head_len = sizeof(TMSMsgHead);
    int pkg_len = 0;

_again:
    if(m->recv_wpos > head_len){
        h = (TMSMsgHead*)(m->recvBuf);
        body_len = xlx_htons(h->body_len);

        //整包大小:14包头、1校验位
        pkg_len = body_len + 14 + 1;
        
        if(m->recv_wpos >= pkg_len){
            //可以解包
            tutu_dispatch(m,h,m->recvBuf,pkg_len);
            //计算剩余多少
            n = m->recv_wpos - pkg_len;
            if(n > 0){
                //解包完，要把后面的数据往前面搬运
                memcpy(m->recvBuf,m->recvBuf + pkg_len,n);
            }
            
            m->recv_wpos = n;
            goto _again;
        }
    }
}

void tutu_socket_recv(TMSContext *m){
    int rsize = 0;
    if(2048 - m->recv_wpos <= 0){
        TUTU_LOGI(TAG, "tms recv buf full!!!!!\n");
        tutu_process(m);
    }else{
        rsize = recv( m->sockfd, m->recvBuf + m->recv_wpos, 2048 - m->recv_wpos,0);
        
        if(rsize > 0){
            xlx_print_hex(XLX_TMS_READ,m->recvBuf + m->recv_wpos,rsize);
            m->recv_wpos += rsize;
            tutu_process(m);
        }else{
            //rsize == 0 ;
            //服务器断开链接
            tmsapi_close_socket(m);
            TUTU_LOGI(TAG, "tms close socket!!!  read size = %d\n",rsize);
        }
    }
}

//连接服务器
int tmsapi_connect_server(TMSContext *m,const char *ip,int port){
    int fd = -1;
    struct sockaddr_in server;
    TUTU_LOGI(TAG, "%s %d	",__func__,__LINE__);
    fd = socket( AF_INET, SOCK_STREAM, 0 );
    if(fd == 0){
        fd = socket( AF_INET, SOCK_STREAM, 0 );
    }
    
    if ( -1 == fd ) {
        TUTU_LOGW(TAG, "tms sock created failt!!" );
        return -1;
    }

    memset( &server, 0, sizeof( struct sockaddr_in ) );
    server.sin_family = AF_INET;
    server.sin_port = xlx_htons(port);
    inet_pton(AF_INET,ip,&server.sin_addr);

    int res = -1;
    m->recv_wpos = 0;
    m->seq = 0;
    res = connect( fd, (struct sockaddr*)&server, sizeof( server ) );
    if( -1 == res ){
        TUTU_LOGW(TAG, "tms sock connect failt!!" );
        fd = -1;
    }
    m->sockfd = fd;
    TUTU_LOGI(TAG, "tms sock connect [%s:%d] OK (fd=%d)", ip, port, fd);
    return fd;
}

//设置等待超时时间
void tmsapi_set_timeout(TMSContext *m,int timeout){
    m->timeout = timeout;
}


void tmsapi_run_data(TMSContext *m){
    fd_set readfds;
    fd_set writefds;
    fd_set excpfds;
    int code = 0;
    struct timeval timeout = {0};

    while(1){
        FD_ZERO(&readfds);
        FD_ZERO(&writefds);
        FD_ZERO(&excpfds);

        if(m->sockfd != -1){
            FD_SET(m->sockfd,&readfds);
            FD_SET(m->sockfd,&excpfds);
        }
                
        timeout.tv_sec = m->timeout;
        code = select(m->sockfd + 1,&readfds,&writefds,&excpfds,&timeout);
        if(code < 0){
            //printf("error!!!\n");
            return;
        }else if(code == 0){
            //printf("timeout!!!\n");
            return;
        }

        if(FD_ISSET(m->sockfd,&readfds)){
            tutu_socket_recv(m);
        }

        if(FD_ISSET(m->sockfd,&excpfds)){
            //printf("socket exception!!!!\n");
            return;
        }
    }
}
